package logx

import (
	"fmt"
	"github.com/toolkits/pkg/errorx"
	"go.uber.org/zap"
	"go.uber.org/zap/zapcore"
	"gopkg.in/natefinch/lumberjack.v2"
	"os"
	"path"
	"runtime"
)

var Logger = new(logger)

type LogConfig struct {
	Filename   string
	MaxSize    int
	MaxBackups int
	MaxAge     int
}

type logger struct {
	zLog          *zap.Logger
	LumberjackLog *lumberjack.Logger
	zapcore.Field
}

func InitLog(conf LogConfig) func() {
	Logger = &logger{
		LumberjackLog: &lumberjack.Logger{
			Filename:   conf.Filename,
			MaxSize:    conf.MaxSize,    // 单个文件最大100M
			MaxBackups: conf.MaxBackups, // 多于 60 个日志文件后，清理较旧的日志
			MaxAge:     conf.MaxAge,     // 一天一切割
		},
	}

	Logger.zLog = zLogInit(Logger)
	Logger.Info("dasdasdsad")

	return func() {
		if err := Logger.LumberjackLog.Close(); err != nil {
			errorx.Bomb(1, "log close fail")
		}
		fmt.Printf("log is stopped \n")
	}
}

func zLogInit(logger *logger) *zap.Logger {
	encoderConfig := zap.NewProductionEncoderConfig()
	// 设置日志记录中时间的格式
	encoderConfig.EncodeTime = zapcore.ISO8601TimeEncoder

	// 日志Encoder 还是JSONEncoder，把日志行格式化成JSON格式的
	encoder := zapcore.NewJSONEncoder(encoderConfig)
	cores := make([]zapcore.Core, 0)
	if logger.LumberjackLog.Filename != "" {
		cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(logger.LumberjackLog), zapcore.InfoLevel))
	} else {
		cores = append(cores, zapcore.NewCore(encoder, zapcore.AddSync(os.Stdout), zapcore.InfoLevel))
	}

	return zap.New(zapcore.NewTee(cores...))
}

func (logger *logger) Info(message string, fields ...zap.Field) {
	callerFields := getCallerInfoForLog()
	fields = append(fields, callerFields...)
	logger.zLog.Info(message, fields...)
}

func (logger *logger) Debug(message string, fields ...zap.Field) {
	callerFields := getCallerInfoForLog()
	fields = append(fields, callerFields...)
	logger.zLog.Debug(message, fields...)
}

func (logger *logger) Error(message string, fields ...zap.Field) {
	callerFields := getCallerInfoForLog()
	fields = append(fields, callerFields...)
	logger.zLog.Error(message, fields...)
}

func (logger *logger) Warn(message string, fields ...zap.Field) {
	callerFields := getCallerInfoForLog()
	fields = append(fields, callerFields...)
	logger.zLog.Warn(message, fields...)
}

func getCallerInfoForLog() (callerFields []zap.Field) {

	pc, file, line, ok := runtime.Caller(2) // 回溯两层，拿到写日志的调用方的函数信息
	if !ok {
		return
	}
	funcName := runtime.FuncForPC(pc).Name()
	funcName = path.Base(funcName) //Base函数返回路径的最后一个元素，只保留函数名

	callerFields = append(callerFields, zap.String("func", funcName), zap.String("file", file), zap.Int("line", line))
	return
}
